/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/getdata.c
 # RCS:         "@(#)$Revision: 1.17 $ $Date: 94/03/10 10:40:06 $"
 # Description: routines to read data from E1430
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char i1430_getdata_fileId[] = "$Header: getdata.c,v 1.17 94/03/10 10:40:06 chriss Exp $";
#endif

/*****************************************************************************
 *
 * Read a block of raw data from module located at logical address, <la>, over 
 * VME bus into <result> whose size is <size> bytes.  Set <adcOverload> if
 * there's an ADC overload in block. Set <adcError> if there is an ADC error 
 * in block. 
 * Return 0 if OK, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_read_raw_data(SHORTSIZ16 la, SHORTSIZ16 *buf, 
		LONGSIZ32 size, SHORTSIZ16 *adcOverload, SHORTSIZ16 *adcError, 
		LONGSIZ32 *actualCnt)
{
  SHORTSIZ16 status, error;
  LONGSIZ32 i, numWords, maxWords, fifoSize;
  int jump;
  volatile USHORTSIZ16 *addr;
  
  addr = (USHORTSIZ16 *)e1430_get_register_address(la, E1430_HP_SEND_DATA_REG);

  /* calculate the number of words to read */
  e1430_get_fifo_block_data_size(la, &fifoSize);
  maxWords = fifoSize/2L;


  if(size > maxWords) {		/* read smaller of the two */
    numWords = maxWords;
  }else{
    numWords = size/2;
  }

  error = i1430_wait_for_block_ready_la(la, &status);
  if(error) {
    if(-1 == error) {		/* device clear from SCPI */
      (void)e1430_abort_meas(e1430_groupID);
      return(0);
    }else{
      return(error);
    }
  }

#ifdef RADISYS
   e1430_clear_berr();
#endif

  if(e1430_try) {     /* E1430_TRY */	
    jump = setjmp(e1430_env);		/* enable TRY-RECOVER */
  }else{
    jump = 0;		/* disable TRY-RECOVER */
  }
  if(!jump) {

#ifdef INTEL_PROC
    {
      SHORTSIZ16 index;
      SHORTSIZ16 datasize;

      /* get index of this module in the glob_modStates array */
      error = i1430_get_index_from_la(la, &index);
      if(error) return (error);
      /* what is size of integer data from module */
      datasize = e1430_modStates[index].dataFormat & ~DATA_FORMAT_DATA_SIZE_MASK;
      for(i=0; i<numWords; i++) {	/* reads the block into buf */
        *buf++ = (SHORTSIZ16)iwpeek(addr);
      }
      E1430_CHECK_BERR

      if(DATA_FORMAT_DATA_SIZE_32 == datasize) {
	/* word swapping done here.  byte swap done in iwpeek */
	SHORTSIZ16 tmp;
	for (i=0; i<numWords; i+=2) {
	    tmp = buf[i];
	    buf[i] = buf[i+1];
	    buf[i+1] = tmp;
	}
      }
    }
#else
    for(i=0; i<numWords; i++) {		/* reads the block into buf */
      *buf++ = iwpeek(addr);
    }
    E1430_CHECK_BERR
#endif

    *actualCnt = numWords * 2;		/* set actual count read */
  
    if(status & E1430_MEAS_STATUS_OVERLOAD) {
      *adcOverload = 1;
    }else{
      *adcOverload = 0;
    }
  
    if(status & E1430_MEAS_STATUS_ADC_ERROR) {
      *adcError = 1; 
    }else{
      *adcError = 0;
    }

  E1430_RECOVER {
    return(i1430_report_bus_error(la, E1430_HP_SEND_DATA_REG));
  }

  return (0);


}


/*****************************************************************************
 *
 * Read a block of data from module located at logical address, <la>, over 
 * VME bus into <result> whose size is <size> bytes.  The results are scaled
 * such that the contents of <result> are in vols in 32 bit float format.
 *
 * Set <adcOverload> if there's an ADC overload in block. Set <adcError> if 
 * there is an ADC error  in block.  
 *
 * Return 0 if OK, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_read_float32_data(SHORTSIZ16 la, FLOATSIZ32 *buf, 
		LONGSIZ32 size, SHORTSIZ16 *adcOverload, SHORTSIZ16 *adcError, 
		LONGSIZ32 *actualCnt)
{
  SHORTSIZ16 status, error;
  LONGSIZ32 i, datablock, numPoints;
  SHORTSIZ16 pointSize;
  int jump;
  FLOATSIZ64 scale;
  SHORTSIZ16 index;
  SHORTSIZ16 datasize;
  SHORTSIZ16 datatype;
  union tag {
    LONGSIZ32 both;
    struct {
#ifdef INTEL_PROC
      USHORTSIZ16 lo;
      USHORTSIZ16 hi;
#else
      USHORTSIZ16 hi;
      USHORTSIZ16 lo;
#endif
    } int16;
  } value; 
  volatile USHORTSIZ16 *addr;

  addr = (USHORTSIZ16 *)e1430_get_register_address(la, E1430_HP_SEND_DATA_REG);

  /* get index of this module in the e1430_modStates array */
  error = i1430_get_index_from_la(la, &index);
  if(error) return (error);

  /* what is size of integer data from module */
  datasize = e1430_modStates[index].dataFormat & ~DATA_FORMAT_DATA_SIZE_MASK;

  /* what is type of integer data from module */
  datatype = e1430_modStates[index].dataFormat & ~DATA_FORMAT_DATA_TYPE_MASK;

  /* calculate the blocksize and number of points */
  e1430_get_fifo_block_data_size(la, &datablock);

  if(datablock > size) {	/* prevent overrun of buffer */
    datablock = size;
  }

  e1430_get_fifo_data_point_size(la, &pointSize);

  error = e1430_get_scale_la(la, &scale);

  if(datatype == DATA_FORMAT_DATA_TYPE_REAL) {
    numPoints = datablock/(LONGSIZ32)pointSize;
  }else{
    numPoints = 2 * datablock/(LONGSIZ32)pointSize;
  }
  
  error = i1430_wait_for_block_ready_la(la, &status);
  if(error) {
    if(-1 == error) {		/* device clear from SCPI */
      (void)e1430_abort_meas(e1430_groupID);
      return(0);
    }else{
      return(error);
    }
  }

#ifdef RADISYS
   e1430_clear_berr();
#endif
  if(e1430_try) {     /* E1430_TRY */	
    jump = setjmp(e1430_env);		/* enable TRY-RECOVER */
  }else{
    jump = 0;		/* disable TRY-RECOVER */
  }
  if(!jump) {

    if(DATA_FORMAT_DATA_SIZE_32 == datasize) {	/* two reads for each point */
      for(e1430_i=0; e1430_i<numPoints; e1430_i++) {		/* reads the block into buf */
        value.int16.hi = iwpeek( addr );
        value.int16.lo = iwpeek( addr );
        *buf++ = (FLOATSIZ32)value.both * (FLOATSIZ32)scale;
      }
    }else{				/* one read to get data */
      for(i=0; i<numPoints; i++) {		/* reads the block into buf */
        *buf++ = (FLOATSIZ32)((SHORTSIZ16)iwpeek(addr)) * (FLOATSIZ32)scale;
      }
    }
    E1430_CHECK_BERR

    *actualCnt = sizeof(FLOATSIZ32) * numPoints;  /* actual byte count read */
  
    if(status & E1430_MEAS_STATUS_OVERLOAD) {
      *adcOverload = 1;
    }else{
      *adcOverload = 0;
    }
  
    if(status & E1430_MEAS_STATUS_ADC_ERROR) {
      *adcError = 1; 
    }else{
      *adcError = 0;
    }

  E1430_RECOVER {
    return(i1430_report_bus_error(la, E1430_HP_SEND_DATA_REG));
  }

  return (0);


}


/*****************************************************************************
 *
 * Read a block of data from module located at logical address, <la>, over 
 * VME bus into <result> whose size is <size> bytes.  The results are scaled
 * such that the contents of <result> are in volts in 64 bit float format.
 *
 * Set <adcOverload> if there's an ADC overload in block. Set <adcError> if 
 * there is an ADC error  in block.  
 *
 * Return 0 if OK, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_read_float64_data(SHORTSIZ16 la, FLOATSIZ64 *buf, 
		LONGSIZ32 size, SHORTSIZ16 *adcOverload, SHORTSIZ16 *adcError, 
		LONGSIZ32 *actualCnt)
{
  SHORTSIZ16 status, error;
  LONGSIZ32 i, datablock, numPoints;
  SHORTSIZ16 pointSize;
  int jump;
  FLOATSIZ64 scale;
  SHORTSIZ16 index;
  SHORTSIZ16 datasize;
  SHORTSIZ16 datatype;
  union tag {
    LONGSIZ32 both;
    struct {
#ifdef INTEL_PROC
      USHORTSIZ16 lo;
      USHORTSIZ16 hi;
#else
      USHORTSIZ16 hi;
      USHORTSIZ16 lo;
#endif
    } int16;
  } value; 
  volatile USHORTSIZ16 *addr;

  addr = (USHORTSIZ16 *)e1430_get_register_address(la, E1430_HP_SEND_DATA_REG);

  /* get index of this module in the e1430_modStates array */
  error = i1430_get_index_from_la(la, &index);
  if(error) return (error);

  /* what is size of integer data from module */
  datasize = e1430_modStates[index].dataFormat & ~DATA_FORMAT_DATA_SIZE_MASK;

  /* what is type of integer data from module */
  datatype = e1430_modStates[index].dataFormat & ~DATA_FORMAT_DATA_TYPE_MASK;

  /* calculate the blocksize and number of points */
  e1430_get_fifo_block_data_size(la, &datablock);

  if(datablock > size) {	/* prevent overrun of buffer */
    datablock = size;
  }

  e1430_get_fifo_data_point_size(la, &pointSize);

  error = e1430_get_scale_la(la, &scale);

  if(datatype == DATA_FORMAT_DATA_TYPE_REAL) {
    numPoints = datablock/(LONGSIZ32)pointSize;
  }else{
    numPoints = 2 * datablock/(LONGSIZ32)pointSize;
  }
  
  error = i1430_wait_for_block_ready_la(la, &status);
  if(error) {
    if(-1 == error) {		/* device clear from SCPI */
      (void)e1430_abort_meas(e1430_groupID);
      return(0);
    }else{
      return(error);
    }
  }

#ifdef RADISYS
   e1430_clear_berr();
#endif
  if(e1430_try) {     /* E1430_TRY */	
    jump = setjmp(e1430_env);		/* enable TRY-RECOVER */
  }else{
    jump = 0;		/* disable TRY-RECOVER */
  }
  if(!jump) {

    if(DATA_FORMAT_DATA_SIZE_32 == datasize) {	/* two reads for each point */
      for(e1430_i=0; e1430_i<numPoints; e1430_i++) {		/* reads the block into buf */
        value.int16.hi = iwpeek( addr );
        value.int16.lo = iwpeek( addr );
        *buf++ = (FLOATSIZ64)value.both * scale;
      }
    }else{				/* one read to get data */
      for(i=0; i<numPoints; i++) {		/* reads the block into buf */
        *buf++ = (FLOATSIZ64)((SHORTSIZ16)iwpeek(addr)) * scale;
      }
    }
    E1430_CHECK_BERR

    *actualCnt = sizeof(FLOATSIZ32) * numPoints;  /* actual byte count read */
  
    if(status & E1430_MEAS_STATUS_OVERLOAD) {
      *adcOverload = 1;
    }else{
      *adcOverload = 0;
    }
  
    if(status & E1430_MEAS_STATUS_ADC_ERROR) {
      *adcError = 1; 
    }else{
      *adcError = 0;
    }

  E1430_RECOVER {
    return(i1430_report_bus_error(la, E1430_HP_SEND_DATA_REG));
  }

  return (0);


}

